import {
  _decorator,
  Component,
  Label,
  resources,
  JsonAsset,
  Prefab,
  Node,
  Vec3,
  instantiate,
  PhysicsSystem2D,
  UITransform,
  director,
  Animation,
} from 'cc';
import { EventBus, TYPE } from './Utils/EventBus';
import { CommonData } from './Utils/CommonData';
const { ccclass, property } = _decorator;

export type WavesType = {
  type: string;
  count: number;
};

export type Waves = {
  time: number;
  zoobies: WavesType[];
};

export type LevelConfig = {
  id: number;
  name: string;
  initSun: number;
  waves: Waves[];
};

@ccclass('GameManager')
export class GameManager extends Component {
  public static _instance: GameManager;

  @property(Node)
  bgyer: Node = null!;

  @property(Label)
  sunLabel: Label = null!;

  @property(Node)
  zombieRoot: Node = null!;

  @property(Prefab)
  lastWave: Prefab = null!;

  @property(Node)
  failurePnlPrefab: Node = null!;

  @property(Prefab)
  normalZombiePrefab: Prefab = null; // 普通僵尸预制体

  sunCount: number = 0;

  zoombieBirthGrids: Vec3[];

  levelConfig: LevelConfig | null = null;

  waveIndex: number = 0; // 当前波次

  timer: number = 0; // 当前游戏时间

  curLevelZomieCount = 0;

  curDeathZombieCount = 0; // 当前死亡僵尸的数量

  interval = 20;

  zmRootPosixX = 0;

  firstZombiePostionX = 0;

  boundonSunChange:any;
  boundonZombieDeath:any

  protected onLoad(): void {
    PhysicsSystem2D.instance.enable = true;
    if (!GameManager._instance) {
      GameManager._instance = this;
    } else {
      this.destroy();
    }
    this.init();
    this.boundonSunChange = this.onSunChange.bind(this)
    this.boundonZombieDeath = this.onZombieDeath.bind(this)
    EventBus.on(TYPE.SUN_CHANGE,this.boundonSunChange );
    EventBus.on(TYPE.ZOMBIE_DEATH, this.boundonZombieDeath);
  }

  protected onDestroy(): void {
    EventBus.off(TYPE.SUN_CHANGE,this.boundonSunChange)
    EventBus.off(TYPE.ZOMBIE_DEATH,this.boundonZombieDeath)
  }

  public async init() {
    this.sunCount = 100;
    this.sunLabel.string = this.sunCount + '';
    this.waveIndex = 0;
    this.timer = 0;
    this.levelConfig = await this.readLevel(CommonData.instance.curLevel);
    this.curLevelZomieCount = this.levelConfig.waves
      .map((v) => v.zoobies.reduce((acc, cur) => cur.count + acc, 0))
      .reduce((acc, cur) => acc + cur);
    const rootPos = this.zombieRoot.getWorldPosition(new Vec3());
    const uiTrans = this.zombieRoot.getComponent(UITransform);
    if (uiTrans) {
      const left = rootPos.x - uiTrans.width * uiTrans.anchorX;
      console.log('草地节点的世界坐标', left);
      this.zmRootPosixX = left;
    }

    console.log('总僵尸：' + this.curLevelZomieCount);
    console.log('总波次：' + this.levelConfig.waves.length);
    console.log('当前关卡配置:' + this.levelConfig);
    this.zoombieBirthGrids = CommonData.instance.gridCenters
      .map((arr) => arr.filter((_, i) => i > 11))
      .reduce((pre, arr: Vec3[]) => {
        pre.push(arr[0]);
        pre.push(arr[1]);
        return pre;
      }, []);
    this.scheduleOnce(() => {
      EventBus.emit(TYPE.SUN_CHANGE, this.sunCount);
    }, 0.2);
    this.schedule(this.getZombiesPosition.bind(this), 2);
  }

  onSunChange(num) {
    this.sunCount = num;
    this.sunLabel.string = num;
  }

  onZombieDeath() {
    this.curDeathZombieCount++;
    if (this.curDeathZombieCount >= this.curLevelZomieCount) {
      console.log('通关结束');
    }
  }

  async readLevel(level: number): Promise<any> {
    return new Promise((resolve, reject) => {
      const path = `levels/level_${level}`;
      resources.load(path, JsonAsset, (err, jsonAssets) => {
        if (err) {
          console.warn(`读取关卡${level}配置报错`, err);
          resolve(null);
          return;
        }
        const levelConfig: LevelConfig = JSON.parse(
          JSON.stringify(jsonAssets.json)
        );
        resolve(levelConfig);
      });
    });
  }

  protected update(dt: number): void {
    if (!this.levelConfig) return;

    this.timer += dt;
    if (this.waveIndex < this.levelConfig.waves.length) {
      const wave = this.levelConfig.waves[this.waveIndex];
      if (this.timer >= wave.time * this.interval) {
        if (
          this.levelConfig.waves[this.levelConfig.waves.length - 1].time -
            this.waveIndex ===
          0
        ) {
          const lastWave = instantiate(this.lastWave);
          if (this.bgyer) {
            lastWave.setParent(this.bgyer);
          }
        }
        this.spawnWave(wave);
        this.waveIndex++;
      }
    }
  }

  async spawnWave(wave: Waves) {
    if (!wave || !wave.zoobies) return;

    // 转成纯 JS 对象，避免 JsonAsset 原型链问题
    const zoobies = JSON.parse(JSON.stringify(wave.zoobies));

    for (const z of zoobies) {
      for (let i = 0; i < z.count; i++) {
        // 随机选择出生行
        const randomIndex = this.getRandomGridIndex() - 1; // 0~8 下标
        const birthPos = this.zoombieBirthGrids[randomIndex];

        if (!birthPos) {
          console.warn(`出生点下标 ${randomIndex} 无效`);
          continue;
        }

        let zombieNode: Node | null = null;

        switch (z.type) {
          case 'NormalZombie':
            zombieNode = instantiate(this.normalZombiePrefab);
            break;
          // 后续可以扩展其他僵尸类型
          default:
            console.warn('未知僵尸类型:', z.type);
            break;
        }

        if (zombieNode) {
          zombieNode.setParent(this.zombieRoot);
          zombieNode.setPosition(birthPos);
          console.log(`生成僵尸: ${z.type}, 坐标:`, birthPos);
        }
        await this.yieldToNext();
      }
    }
  }

  private yieldToNext(): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, 1000));
  }

  spawnZombie(pos: Vec3) {}

  getRandomGridIndex(): number {
    return Math.floor(Math.random() * 9) + 1;
  }

  getZombiesPosition() {
    let recentZombieX = Math.min(
      ...this.zombieRoot.children
        .filter((node: Node) => /Zombie/gi.test(node.name))
        .map((zm) => this.getLeftWorldX(zm))
    );
    if (recentZombieX < this.zmRootPosixX - 20) {
      this.failurePnlPrefab.active = true;
      this.failurePnlPrefab
        .getChildByName('bg')
        .getComponent(Animation)
        .play('appear');
      this.scheduleOnce(() => {
        director.pause();
      }, 1);
    }
  }

  getLeftWorldX(node: Node) {
    const pos = node.getWorldPosition(new Vec3());
    const ui = node.getComponent(UITransform);
    if (!ui) return;
    return pos.x - ui.width * ui.anchorX;
  }

  clickEditGame() {
    director.loadScene('home');
  }

  clickResetGame() {
    console.log('正在开发中');
  }
}
